home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / HippoDraw / HippoDrawSrc1.1 / Hippo.subproj / Plot.m < prev    next >
Encoding:
Text File  |  1992-04-25  |  23.7 KB  |  1,070 lines

  1. /* Plot.m  by Jonas Karlsson, July 1990 
  2.  *
  3.  * Copyright (C)  1991  The Board of Trustees of
  4.  * The Leland Stanford Junior University. All Rights Reserved.
  5.  */
  6.  
  7. #import "Plot.h"
  8.  
  9. const char Plot_h_rcsid[] = PLOT_H_ID;
  10. const char Plot_m_rcsid[] = "$Id: Plot.m,v 1.20 1992/04/23 17:15:57 pfkeb Rel $";
  11.  
  12. #import <appkit/Panel.h>
  13. #import <objc/List.h>
  14. #import <objc/Storage.h>
  15.  
  16. #import "HGraphicView.h"
  17. #import "HTuple.h"
  18.  
  19. #import <appkit/nextstd.h>
  20. #import <math.h>
  21. #import <float.h>
  22. #import <dpsclient/wraps.h>
  23.  
  24. #define INDEX_VERSION 2
  25. #define CURRENT_VERSION INDEX_VERSION
  26.  
  27. @implementation Plot
  28.  
  29. static unsigned int plotNum = 0;
  30.  
  31. static NXAtom namePlot() 
  32. {
  33.     char buffer[256];
  34.     
  35.     sprintf( buffer, "HippoPlot.%d", plotNum++);
  36.     return NXUniqueString(buffer);
  37. }
  38.     
  39. static void setMarginRect( NXRect *margins, NXRect *bounds, int grid )
  40. {    
  41.     NXSetRect (margins, 
  42.     0.18 * bounds->size.width,
  43.     0.18 * bounds->size.height,
  44.     bounds->size.width * (1.0 - .26),
  45.     bounds->size.height * (1.0 - .26));
  46.     if ( margins->size.width/grid > 3.001 ) {
  47.         margins->origin.x = bounds->origin.x
  48.                   + MAX( grid*floor( margins->origin.x/grid ), grid );
  49.     margins->size.width = grid*floor( margins->size.width/grid );
  50.     } else {
  51.         margins->origin.x += bounds->origin.x;
  52.     }
  53.     if ( margins->size.height/grid > 3.001) {
  54.         margins->origin.y = bounds->origin.y
  55.                    + MAX( grid*floor( margins->origin.y/grid ), grid );
  56.     margins->size.height = grid*floor( margins->size.height/grid );
  57.     } else {
  58.         margins->origin.y += bounds->origin.y;
  59.     }
  60.     
  61. }
  62. + initialize
  63. {
  64.     [self setVersion:CURRENT_VERSION];
  65.     return self;
  66. }
  67. - init
  68. {
  69.     [super init ];
  70.     uniqueName = namePlot();
  71.     return self;
  72. }
  73. - (const char *)name
  74. {
  75.     return uniqueName;
  76. }
  77. - getDispType:(graphtype_t *) type
  78. {
  79.      *type = h_getDispType(disp);
  80.      return self;
  81. }
  82.  
  83. - setDispType:(graphtype_t *) type
  84. {
  85.     graphtype_t         oldtype;
  86.     const char         *string;
  87.     int                 i;
  88.  
  89.     oldtype = h_getDispType(disp);
  90.     h_setDispType(disp, *type);
  91.     if ((oldtype == HISTOGRAM) && (*type != HISTOGRAM)) {
  92.     i = h_getBinding(disp, XAXIS);
  93.     h_bind(disp, YAXIS, i);
  94.     string = h_getNtLabel([hTuple ntuple], i);
  95.     [self NameAxisY:string];
  96.     }
  97.     if ((oldtype != HISTOGRAM) && (*type == HISTOGRAM)) {
  98.     h_setDrawType(disp, BOX);
  99.     [self NameAxisY:"Entries per bin"];
  100.     }
  101.     return self;
  102. }
  103.  
  104. - setGraphicView:anObject
  105. {
  106.     graphicView = anObject;
  107.     return self;
  108. }
  109. - graphicView
  110. {
  111.     return graphicView;
  112. }
  113. - setHTuple: ht withDisplay:(display) d1
  114. {
  115.     NXRect      margins;
  116.     int        grid;
  117.  
  118.     disp = d1;
  119.     [self replaceTupleWith:ht];
  120.     h_getDrawRect(disp, (rectangle *) &bounds);
  121.     grid = [graphicView gridSpacing];
  122.     setMarginRect(&margins, &bounds, grid );
  123.     h_setMarginRect(disp, (rectangle *) & margins);
  124.     return self;
  125. }
  126. - setRefFlag:(BOOL) flag
  127. {
  128.     h_setNtByRef( disp, flag, NULL );
  129.     return self;
  130. }
  131. - setFixBinsFlag:(BOOL)flag
  132. {
  133.     fixBinsFlag = flag;
  134.     h_setFixedBins( disp, fixBinsFlag );
  135.     return self;
  136. }
  137. - setRefFilename:(const char *)filename
  138. {
  139.     if (!filename) return self;    /* if filename is not legal, return */
  140.     if ( !reffilename ) {
  141.         NX_ZONEMALLOC( [self zone], reffilename, char, strlen(filename)+1 );
  142.     } else {
  143.         NX_ZONEREALLOC( [self zone], reffilename, char, strlen(filename)+1 );
  144.     }
  145.     strcpy( reffilename, filename );
  146.     return self;
  147. }
  148. - changeRefFileNameIfValid:(const char *)filename
  149. {
  150.     if ( !hTuple ) {
  151.         return self;
  152.     }
  153.     if ( [hTuple isFakeFilename] ) {
  154.     if ( !reffilename ) {
  155.         NX_ZONEMALLOC( [self zone], reffilename, char,
  156.                        strlen(filename)+1 );
  157.     } else {
  158.         NX_ZONEREALLOC( [self zone], reffilename, char,
  159.                         strlen(filename)+1 );
  160.     }
  161.     strcpy( reffilename, filename );
  162.     [hTuple setFilename:filename];
  163.     }
  164.     return self;
  165. }
  166. - replaceTupleWith: ht
  167. {
  168.     ntuple    tuple;
  169.     
  170.     hTuple = ht;
  171.     tuple = (hTuple != nil)  ? [hTuple ntuple] : NULL ;
  172.     h_bindNtuple(disp, tuple );
  173.     if ( !tuple ) return self;
  174.     h_setTitle(disp, h_getNtTitle(tuple) );
  175.     [self setRefFilename:[hTuple filename]];
  176.     [self setRefFlag:[hTuple isRef]];
  177.     ntindex = [hTuple index];
  178.     return self;
  179. }
  180. - replace:oldTuple with:newTuple
  181. {
  182.     if ( oldTuple == hTuple ) {
  183.     [self replaceTupleWith:newTuple];
  184.     }
  185.     return self;
  186. - closeTuple
  187. {
  188.     ntuple    tuple;
  189.     
  190.     refFlag = h_getNtByRef(disp);
  191.     fixBinsFlag = h_getFixedBins(disp);
  192.     h_setFixedBins(disp, YES);
  193.     hTuple = nil;
  194.     tuple = NULL;
  195.     h_bindNtuple(disp, tuple );
  196.     return self;
  197. }
  198. - bindReference
  199. {
  200.     if ( reffilename == NULL ) return self;
  201.     if ( !hTuple ) {
  202.     hTuple = [ graphicView hTupleForFile:reffilename index:ntindex];
  203.     }
  204.     if ( disp == NULL ) return self;
  205.     [self replaceTupleWith:hTuple];
  206.     if ( !hTuple ) return self;
  207.     
  208.     h_setFixedBins( disp, fixBinsFlag );
  209.     return self;
  210. }
  211.  
  212. - bindCuts
  213. {
  214.     id            copyStor;
  215.     id            plotList;
  216.     id            plot;
  217.     cutStorElem        *cut;
  218.     dependStorElem    *depend;
  219.     func_id        cut_func;
  220.     unsigned        i, j;
  221.     BOOL        isBound;
  222.     
  223.     if ( cutPlotStor ) {
  224.     copyStor = [cutPlotStor copy ];
  225.     [cutPlotStor empty];
  226.     while ( (cut_func = h_nextCut(disp, NULL) ) ) {
  227.         h_deleteCut(disp, cut_func);
  228.     }
  229.     isBound = NO;
  230.     i = [copyStor count];
  231.     while ( i-- ) {
  232.         cut = [copyStor elementAt: i];
  233.         if ( cut->plot ) {
  234.         [self addCutPlot:cut->plot];
  235.         isBound = YES;
  236.         } else {
  237.         plotList = [graphicView plotList];
  238.         j = [plotList count];
  239.         while ( j-- ) {
  240.             plot = [plotList objectAt:j];
  241.             if ( cut->name == [plot name] ) {
  242.             [self addCutPlot:plot];
  243.             isBound = YES;
  244.             break;
  245.             }
  246.         }
  247.         }
  248.     }
  249.     if ( !isBound ) {
  250.         h_setFixedBins( disp, YES );
  251.     }
  252.     [copyStor free];
  253.     }
  254.     if ( dependStor ) {
  255.         copyStor = [dependStor copy];
  256.     [ dependStor empty];
  257.     i = [copyStor count];
  258.     while ( i-- ) {
  259.         depend = [copyStor elementAt:i];
  260.         if ( depend->plot ) {
  261.             plotList = [depend->plot plotList];
  262.         j = [plotList indexOf:self];
  263.         if ( j == NX_NOT_IN_LIST ) {
  264.             [depend->plot addCutPlot:self];
  265.         } else {
  266.             [dependStor addElement:depend];
  267.         }
  268.         } else {
  269.             plotList = [graphicView plotList];
  270.         j = [plotList count];
  271.         while ( j-- ) {
  272.             plot = [plotList objectAt:j];
  273.             if ( depend->name == [plot name] ) {
  274.                 [plot addCutPlot:self];
  275.             break;
  276.             }
  277.         }
  278.         }
  279.     }
  280.     [graphicView addCut:self];
  281.     }
  282.     return self;
  283. }
  284.  
  285. - hTuple
  286. {
  287.     return hTuple;
  288. }
  289. - (ntuple) ntuple
  290. {
  291.     return [hTuple ntuple];
  292. }
  293. - addHTupleToList:tlist
  294. {
  295.     if ( hTuple ) {
  296.     [tlist addObjectIfAbsent:hTuple];
  297.     }
  298.     return self;
  299. }
  300.  
  301. - addPlotToList:list
  302. {
  303.     [list addObjectIfAbsent:self];
  304.     return self;
  305. }
  306. - (display) histDisplay
  307. {
  308.     return disp;
  309. }
  310.  
  311. - setTitle:(char *) title
  312. {
  313.   h_setTitle(disp, title);
  314.  
  315.   return self;
  316. }
  317. - (char *) title
  318. {
  319.     return ((char *) h_getTitle( disp ) );
  320. }
  321. - NameAxisX:(const char *)AxisName
  322. {
  323.     h_setAxisLabel(disp, XAXIS, AxisName);
  324.     return self;
  325. }
  326. - (const char *) axisLabelX
  327. {
  328.     return h_getAxisLabel(disp, XAXIS );
  329. }
  330. - (const char *) axisLabelY
  331. {
  332.     return h_getAxisLabel(disp, YAXIS );
  333. }
  334. - NameAxisY:(const char *)AxisName
  335. {
  336.     h_setAxisLabel(disp, YAXIS, AxisName);
  337.     return self;
  338. }
  339. - NameAxisW:(const char *)AxisName
  340. {
  341.     h_setAxisLabel(disp, WEIGHT, AxisName);
  342.     return self;
  343. }
  344.  
  345. - NameAxisXE:(const char *)AxisName
  346. {
  347.     h_setAxisLabel(disp, XERROR, AxisName);
  348.     return self;
  349. }
  350.  
  351. - NameAxisYE:(const char *)AxisName
  352. {
  353.     h_setAxisLabel(disp, YERROR, AxisName);
  354.     return self;
  355. }
  356.  
  357. - bindAxisX:(int *)dataDim
  358. {
  359.     h_bind(disp, XAXIS, *dataDim );
  360.     h_setAxisLabel(disp, XAXIS, h_getNtLabel([hTuple ntuple],*dataDim) );
  361.     return self;
  362. }
  363. - bindAxisY:(int *)dataDim
  364. {
  365.     h_bind(disp, YAXIS, *dataDim );
  366.     h_setAxisLabel(disp, YAXIS, h_getNtLabel([hTuple ntuple],*dataDim) );
  367.     return self;
  368. }
  369. - bindAxisW:(int *)dataDim
  370. {
  371.     h_bind(disp, WEIGHT, *dataDim );
  372.     return self;
  373. }
  374.  
  375. - bindAxisXE:(int *)dataDim
  376. {
  377.     h_bind(disp, XERROR, *dataDim );
  378.     return self;
  379. }
  380.  
  381. - bindAxisYE:(int *)dataDim
  382. {
  383.     h_bind(disp, YERROR, *dataDim );
  384.     return self;
  385. }
  386.  
  387. - setLogScaleX:(int *)yesOrNo
  388. {    
  389.     h_setLogAxis(disp,XAXIS,*yesOrNo);
  390.     return self;
  391. }
  392. - (BOOL) isLogScaleX
  393. {
  394.     BOOL    val;
  395.     
  396.     val = h_getLogAxis(disp, XAXIS);
  397.     return val;
  398. }
  399. - setLogScaleY:(int *)yesOrNo
  400. {    
  401.     h_setLogAxis(disp,YAXIS,*yesOrNo);
  402.     return self;
  403. }
  404. - (BOOL) isLogScaleY
  405. {
  406.     BOOL    val;
  407.     
  408.     val = h_getLogAxis(disp, YAXIS);
  409.     return val;
  410. }
  411. - setTitlesFlag:(int *)yesOrNo
  412. {
  413.     h_setDrawTitles( disp, *yesOrNo);
  414.     return self;
  415. }
  416. - (int) titlesFlag
  417. {
  418.     return h_getDrawTitles(disp);
  419. }
  420.  
  421. - setAxesFlag:(int *)yesOrNo
  422. {
  423.     h_setDrawAxes( disp, *yesOrNo );
  424.     return self;
  425. }
  426. - (int) axesFlag
  427. {
  428.     return h_getDrawAxes( disp );
  429. }
  430. - setAutoScaleX:(int *)yesOrNo
  431. {    
  432.      h_setAutoScale(disp,XAXIS,*yesOrNo);
  433.      return self;
  434. }
  435. - setAutoScaleY:(int *)yesOrNo
  436. {    
  437.      h_setAutoScale(disp,YAXIS,*yesOrNo);
  438.      return self;
  439. }
  440.  
  441. - setCutHistFlag: (BOOL) yesOrNo
  442. {
  443.     cutHistFlag = yesOrNo;
  444.     return self;
  445. }
  446.  
  447. - (BOOL) isCutHist
  448. {
  449.     return cutHistFlag;
  450. }
  451.  
  452. - setRangeForAxisX:(NXPoint *)p
  453. {
  454.     h_setRange(disp, XAXIS, p->x, p->y );
  455.     return self;
  456. }
  457. - getRangeForAxisX:(NXPoint *)p
  458. {
  459.     if ( h_getAutoScale( disp, XAXIS ) ) {
  460.         h_setDirty( disp );
  461.     h_bin( disp ); /* in case it hasn't been displayed */
  462.     }
  463.     h_getRange(disp, XAXIS, &p->x, &p->y );
  464.     return self;
  465. }
  466. - setRangeForAxisY:(NXPoint *)p
  467. {
  468.     h_setRange(disp, YAXIS, p->x, p->y );
  469.     return self;
  470. }
  471. - getRangeForAxisY:(NXPoint *)p
  472. {
  473.     if ( h_getAutoScale(disp,YAXIS) ) {
  474.         if ( h_getDispType(disp) == HISTOGRAM ) {
  475.         h_setDirty( disp );
  476.         h_bin( disp ); /* in case it hasn't been displayed */
  477.         h_getBinExtreme(disp, &p->x, &p->y );
  478.     } else {
  479.         h_autoScale(disp);
  480.         h_getRange(disp, YAXIS, &p->x, &p->y );
  481.     }
  482.     } else {
  483.     h_getRange(disp, YAXIS, &p->x, &p->y );
  484.     }
  485.     return self;
  486. }
  487. - getRangeForAxis:(binding_t) axis low:(float *) xl high:(float *) xh
  488. {
  489.     
  490.     if ( h_getAutoScale( disp, axis ) && (axis == YAXIS) ) {
  491.         if ( h_getDispType(disp) == HISTOGRAM ) {
  492.         h_setDirty( disp );
  493.         h_bin( disp ); /* in case it hasn't been displayed */
  494.         h_getBinExtreme(disp, xl, xh );
  495.     } else {
  496.         h_autoScale(disp);
  497.         h_getRange(disp, YAXIS, xl, xh );
  498.     }
  499.     } else {
  500.     h_getRange(disp, axis, xl, xh );
  501.     }
  502.     return self;
  503. }
  504. - setRangesFrom:plot
  505. {
  506.     NXPoint    range;
  507.     graphtype_t    plot_t;
  508.     float    plot_w, my_w;
  509.     int        flag = 0;
  510.  
  511.     if ( plot == self ) {
  512.         return self;
  513.     }
  514.     [plot getRangeForAxisX:&range];
  515.     [self setRangeForAxisX:&range];
  516.     [self setAutoScaleX:&flag];
  517.     [plot getRangeForAxisY:&range];
  518.     if ( h_getDispType(disp) == HISTOGRAM ) {
  519.         [plot getDispType:&plot_t];
  520.     if ( plot_t == HISTOGRAM ) {
  521.         plot_w = [plot widthForAxis:XAXIS];
  522.         my_w = h_getBinWidth(disp, XAXIS);
  523.         range.x = range.x*(my_w/plot_w);
  524.         range.y = range.y*(my_w/plot_w);
  525.         [self setRangeForAxisY:&range];
  526.         [self setAutoScaleY:&flag];
  527.     }
  528.     } else {
  529.     [self setRangeForAxisY:&range];
  530.     [self setAutoScaleY:&flag];
  531.     }
  532.     return self;
  533. }
  534. - getRangeForAxisY:(NXPoint *)range normalizedTo:plot
  535. {
  536.     graphtype_t    plot_t;
  537.     float    plot_w, my_w;
  538.     
  539.     [self getRangeForAxisY:range];
  540.     
  541.     [plot getDispType:&plot_t];
  542.     if ( h_getDispType(disp) != HISTOGRAM || 
  543.                       plot_t != HISTOGRAM    ) {
  544.         return self;
  545.     }
  546.     plot_w = [plot widthForAxis:XAXIS];
  547.     my_w = h_getBinWidth(disp, XAXIS);
  548.     range->x *= (plot_w/my_w);
  549.     range->y *= (plot_w/my_w);
  550.     return self;
  551. }
  552. - (float)widthForAxis:(binding_t) axis
  553. {
  554.     return h_getBinWidth(disp, axis);
  555. }
  556. - setNumBinsForAxisX:(int *) n
  557. {
  558.    h_setBinNum(disp, XAXIS, *n );
  559.    return self;
  560. }
  561.  
  562. - setNumBinsForAxisY:(int *) n
  563. {
  564.    h_setBinNum(disp, YAXIS, *n );
  565.    return self;
  566. }
  567.  
  568. - (int)numBinsForAxis:(binding_t) axis
  569. {
  570.     return h_getBinNum(disp, axis);
  571. }
  572. - setDrawType:(drawtype_t *) type
  573. {
  574.     h_setDrawType(disp, *type);
  575.     return self;
  576. }
  577. - getDrawType:(drawtype_t *) type
  578. {
  579.     *type = h_getDrawType(disp);
  580.     return self;
  581. }
  582. - setColorType:(int *)onOff
  583. {
  584.      int i;
  585.      
  586.      if ( *onOff )
  587.       h_orDrawType(disp, COLOR);
  588.      else
  589.      {
  590.       i = h_getDrawType(disp);
  591.       i = i & (~COLOR);
  592.       h_setDrawType(disp, i);
  593.      }
  594.      return self;
  595. }
  596. - draw
  597. {
  598.         NXRect margins;
  599.         int   grid;
  600.         
  601.         if (bounds.size.width < 1.0 || bounds.size.height < 1.0)
  602.         return self;
  603.  
  604.         if (!NXEqualColor([self fillColor], NX_COLORCLEAR)) {
  605.         [self setFillColor];
  606.         NXRectFill(&bounds);
  607.         }
  608.         if (!NXEqualColor([self lineColor], NX_COLORCLEAR)) {
  609.         [self setLineColor];
  610.         }
  611.        if ( (NXDrawingStatus == NX_PRINTING) && (linewidth < 0.15) ) {
  612.             PSsetlinewidth(0.15);     /* in case going to Linotronic (R) */
  613.         }
  614.     
  615.         h_setDrawRect (disp, (rectangle *) &bounds );
  616.     if ( graphicView ) { 
  617.         grid = [graphicView gridSpacing];
  618.     } else {
  619.         grid = 1;
  620.     }
  621.         setMarginRect( &margins, &bounds, grid );
  622.         h_setMarginRect (disp, (rectangle *) &margins);
  623.  
  624.  /*
  625.  * do shading in case of cut plot. Must do after plotting, since h_plot
  626.  *  sets up margins, autoscales, etc.
  627.  * h_shade will keep shading inside bounds of plot.
  628.  */
  629.     if ( cutHistFlag && (disp != NULL) && (cutParms.cutFunc != NULL) )
  630.     {
  631.          switch (cutParms.cutCode)
  632.          {
  633.          case 0:
  634.           h_shade(disp, -FLT_MAX, cutParms.cutValue1);
  635.           break;
  636.          case 1:
  637.           h_shade(disp, cutParms.cutValue1, FLT_MAX);
  638.           break;
  639.          case 2:
  640.           h_shade(disp, cutParms.cutValue1, cutParms.cutValue2);
  641.           break;
  642.          case 3:
  643.           h_shade(disp, -FLT_MAX, cutParms.cutValue1);
  644.           h_shade(disp, cutParms.cutValue2, FLT_MAX);
  645.           break;
  646.          }          
  647.     }
  648.  
  649.  /*
  650.   * draw plot last, so shading doesn't cover it.
  651.   */
  652.         h_plot(disp);
  653.  
  654.         return self;
  655. }
  656. - print
  657. {
  658.     h_print(disp);
  659.     return self;
  660. }
  661.  
  662. - setBounds:(const NXRect *)aRect
  663. {
  664.     NXRect margins;
  665.     int        grid;
  666.     
  667.     bounds = *aRect;
  668.     h_setDrawRect(disp, (rectangle *)  &bounds);
  669.     grid = [graphicView gridSpacing];
  670.     setMarginRect( &margins, &bounds, grid );    
  671.     h_setMarginRect (disp, (rectangle *) &margins);
  672.     return self;
  673. }
  674.  
  675.  
  676. - sizeToNaturalAspectRatio
  677. {
  678.     NXRect    defaultBox;
  679.     
  680.     [graphicView calcDefaultPlotSize:&defaultBox];
  681.     bounds.origin.y += ( NX_HEIGHT(&bounds) - NX_HEIGHT(&defaultBox) );
  682.     bounds.size.height = NX_HEIGHT(&defaultBox);
  683.     bounds.size.width = NX_WIDTH(&defaultBox);
  684.     [self setBounds:&bounds];
  685.     return self;
  686. }
  687. /* Methods supporting managing cutPlots to this plot */
  688. - addCutPlot: cutPlot
  689. {
  690.     cutStorElem        newcut, *cut;
  691.     dependStorElem    *depend;
  692.     cutParmType         parms;
  693.     int            irc;
  694.     unsigned        i, count;
  695.     
  696.     if ( self == cutPlot ) {
  697.         return self;
  698.     }
  699.     if ( [cutPlot ntuple] != [hTuple ntuple] ) {
  700.         irc = NXRunAlertPanel( "Open",
  701.                    "Attempt to apply cut from different ntuple",
  702.                            "OK", NULL, NULL);
  703.         return self;
  704.     }
  705.     if ( !cutPlotStor ) {
  706.         cutPlotStor = [[Storage allocFromZone:[self zone]] initCount:0
  707.                         elementSize:sizeof(cutStorElem)
  708.                     description:"@%*"];
  709.     }
  710.     
  711.  /* Check if this cutPlot has already been added */
  712.     count = [cutPlotStor count];
  713.     for ( i = 0; i < count; i++ ) {
  714.         cut = [cutPlotStor elementAt:i];
  715.     if ( cut->plot == cutPlot ) {
  716.         return self;
  717.     }
  718.     }
  719.     
  720.  /* Add cutPlot to this plot's list of cuts */
  721.     [cutPlot addCutDepend:self ];
  722.     [cutPlot getCutParms:&parms];
  723.     newcut.plot = cutPlot;
  724.     newcut.name = [cutPlot name];
  725.     newcut.function = h_addCut(disp, parms.cutFunc, parms.varIndex, 
  726.                        parms.cutValue1, parms.cutValue2);
  727.     [cutPlotStor addElement:&newcut];
  728.  
  729.  /* If this plot is a cutting Plot, then add cutPlot to those plots */
  730.     if ( !dependStor ) {
  731.         return self;
  732.     }
  733.     i = [dependStor count];
  734.     if ( !i ) {
  735.         return self;
  736.     }
  737.     while ( i-- ) {
  738.         depend = [dependStor elementAt:i];
  739.     [depend->plot addCutPlot:cutPlot];
  740.     }
  741.     return self;
  742. }
  743. - changeCutPlot:cutPlot
  744. {
  745.     cutStorElem        *cut;
  746.     cutParmType         parms;
  747.     int            i, count;
  748.     
  749.     count = [cutPlotStor count];
  750.     for ( i = 0; i < count; i ++ ) {
  751.         cut = [cutPlotStor elementAt:i];
  752.     if ( cut->plot == cutPlot ) {
  753.         [cutPlot getCutParms:&parms];
  754.         h_changeCut(disp, cut->function,
  755.                     parms.cutValue1, parms.cutValue2);
  756.         break;
  757.     }
  758.     }
  759.     return self;
  760. }
  761. - removeCutPlot:cutPlot
  762. {
  763.     cutStorElem        *cut;
  764.     int            i, count;
  765.     
  766.     
  767.     count = [cutPlotStor count];
  768.     for ( i = 0; i < count; i ++ ) {
  769.         cut = [cutPlotStor elementAt:i];
  770.     if ( cut->plot == cutPlot ) {
  771.         [cutPlot removeCutDepend:self];
  772.             h_deleteCut( disp, cut->function );
  773.         [cutPlotStor removeAt:i];
  774.         break;
  775.     }
  776.     }
  777.     return self;
  778. }
  779. - removeAllCuts
  780. {
  781.     cutStorElem        *cut;
  782.     int            i, count;
  783.     
  784.     
  785.     count = [cutPlotStor count];
  786.     for ( i = 0; i < count; i ++ ) {
  787.         cut = [cutPlotStor elementAt:i];
  788.     [cut->plot removeCutDepend:self];
  789.     h_deleteCut( disp, cut->function );
  790.     }
  791.     [cutPlotStor empty];
  792.     return self;
  793. }
  794. - cutList
  795. {
  796.     cutStorElem        *cut;
  797.     unsigned    i, count;
  798.     
  799.     count = [cutPlotStor count];
  800.     if ( !count ) {
  801.         return nil;
  802.     }
  803.     
  804.     if ( cutPlotList == nil ) {
  805.         cutPlotList = [[List allocFromZone:[self zone]] initCount:0];
  806.     } else {
  807.         [cutPlotList empty];
  808.     }
  809.     for ( i = 0; i < count; i++ ) {
  810.         cut = [cutPlotStor elementAt:i];
  811.     [cutPlotList addObject:cut->plot];
  812.     }
  813.     return cutPlotList;
  814. }
  815. - (BOOL) hasCut
  816. {
  817.     return ( [cutPlotStor count] ? YES : NO );
  818. }
  819. /* Methods used to support plot being used for display for a cut function */
  820. - setCutParms:(cutParmType *) parms
  821. {
  822.     cutParms.cutFunc   = NXCopyStringBuffer( parms->cutFunc );
  823.     cutParms.varIndex  = parms->varIndex;
  824.     cutParms.cutValue1 = parms->cutValue1;
  825.     cutParms.cutValue2 = parms->cutValue2;
  826.     cutParms.cutCode   = parms->cutCode;
  827.     if ( cutParms.cutCode < 2 ) {
  828.         cutParms.blkSize = 2;
  829.     } else {
  830.         cutParms.blkSize = 3;
  831.     }
  832.     
  833.     return self;
  834. }
  835. - getCutParms:(cutParmType *) parms
  836. {
  837.     parms->cutFunc   = cutParms.cutFunc;
  838.     parms->varIndex  = cutParms.varIndex;
  839.     parms->cutValue1 = cutParms.cutValue1;
  840.     parms->cutValue2 = cutParms.cutValue2;
  841.     parms->cutCode   = cutParms.cutCode;
  842.     parms->blkSize   = cutParms.blkSize;
  843.  
  844.     return self;
  845. }    
  846. - addCutDepend:sender
  847. {
  848.     dependStorElem    new, *old;
  849.     unsigned int    i;
  850.     
  851.     if ( !dependStor ) {
  852.         dependStor = [[Storage allocFromZone:[self zone]] initCount:0
  853.                              elementSize:sizeof(dependStorElem)
  854.                          description:"@%"];
  855.     }
  856.     i = [dependStor count];
  857.     while ( i-- ) {
  858.         old = [dependStor elementAt:i];
  859.     if ( old->plot == sender ) {
  860.         return self;
  861.     }
  862.     }
  863.     new.plot = sender;
  864.     new.name = [sender name];
  865.     [dependStor addElement:&new];
  866.     return self;
  867. }
  868. - removeCutDepend:sender
  869. {
  870.     dependStorElem    *old;
  871.     unsigned int    i;
  872.     
  873.     i = [dependStor count];
  874.     while ( i-- ) {
  875.         old = [dependStor elementAt:i];
  876.     if ( old->plot == sender ) {
  877.         [dependStor removeAt:i];
  878.         return self;
  879.     }
  880.     }
  881.     return self;
  882. }
  883. - (unsigned) dependCount
  884. {
  885.     if ( !dependStor ) {
  886.         return 0;
  887.     }
  888.     return [dependStor count];
  889. }
  890. - dependList;
  891. {
  892.     dependStorElem    *old;
  893.     unsigned int    i;
  894.     
  895.     if ( !dependList ) {
  896.         dependList = [[List allocFromZone:[self zone]] initCount:0];
  897.     }
  898.     [dependList empty];
  899.     i = [dependStor count];
  900.     while ( i-- ) {
  901.         old = [dependStor elementAt:i];
  902.     [dependList addObject:old->plot];
  903.     }
  904.     return dependList;
  905. }
  906. - (BOOL) isCutPlot
  907. {
  908.     return cutHistFlag;
  909. }
  910. /* Methods supporting Archiving and de-Archiving */
  911. - write:(NXTypedStream *) ts
  912. {
  913.     cutStorElem        *cut;
  914.     dependStorElem    *old;
  915.     display             dlist[] = {NULL, NULL};
  916.     char        *data;
  917.     int            len, lenref;
  918.     int            i;
  919.  
  920.     [super write:ts];
  921.  
  922.  /* change some flags for storage to stream */
  923.     refFlag = h_getNtByRef(disp);
  924.     fixBinsFlag = h_getFixedBins(disp);
  925.     h_setFixedBins(disp, YES);
  926.     h_setNtByRef(disp, YES, reffilename );
  927.     lenref = strlen(reffilename);
  928.  
  929.  /* write display to buffer */
  930.     len = h_dispSize( disp );
  931.     NX_ZONEMALLOC( [self zone], data, char, len );
  932.     dlist[0] = disp;
  933.     if ( h_writeMem( data, len, dlist, NULL ) ) {
  934.         printf( "Could not write buffer\n" );
  935.     return self;
  936.     }
  937.  
  938.  /* restore display in case we are doing copy */
  939.     h_setNtByRef( disp, refFlag, NULL );
  940.     h_setFixedBins( disp, fixBinsFlag );
  941.         
  942.  /* Now archive Plot object to typed stream */
  943.  
  944.     NXWriteTypes( ts, "ccii",    &refFlag, &fixBinsFlag, &len, &lenref );
  945.     NXWriteType(  ts, "*",       &reffilename );
  946.     if ( [Plot version] >= INDEX_VERSION ) {
  947.         NXWriteType( ts, "i", &ntindex );
  948.         NXWriteObjectReference(ts, hTuple);
  949.     }
  950.     NXWriteArray( ts, "c",       len, data );
  951.     NXWriteType(  ts, "c",       &cutHistFlag);
  952.     if ( cutHistFlag ) {
  953.     len = strlen( cutParms.cutFunc );
  954.         NXWriteType( ts, "i",       &len );
  955.     NXWriteType( ts, "{*iffi}", &cutParms ); 
  956.     NXWriteType( ts, "i",       &cutNumber);
  957.     }
  958.     
  959.     i = [cutPlotStor count];
  960.     NXWriteType( ts, "i", &i );
  961.     while ( i-- ) {
  962.         cut = [cutPlotStor elementAt:i];
  963.     NXWriteObjectReference(ts, cut->plot );
  964.     if ( [Plot version] >= INDEX_VERSION ) {
  965.         cut->name = [cut->plot name];
  966.         NXWriteType( ts, "%", &cut->name );
  967.     }
  968.     }
  969.     if ( dependStor ) {
  970.         i = [dependStor count];
  971.     } else {
  972.         i = 0;
  973.     }
  974.     NXWriteType( ts, "i", &i);
  975.     while ( i-- ) {
  976.         old = [dependStor elementAt:i];
  977.     NXWriteObjectReference( ts, old->plot);
  978.     if ( [Plot version] >= INDEX_VERSION ) {
  979.         old->name = [old->plot name];
  980.         NXWriteType( ts, "%", &old->name );
  981.     }
  982.     }
  983.     
  984.     free( data );    
  985.     
  986.     return self;
  987. }
  988. - read:(NXTypedStream *) ts
  989. {
  990.     cutStorElem        cut;
  991.     dependStorElem    new;
  992.     ntuple        *ntlist;
  993.     display        *dlist;
  994.     char        *data;
  995.     int            len, lenref;
  996.     int            i, count;
  997.     
  998.     [super read:ts];
  999.     uniqueName = namePlot();
  1000.     NXReadTypes( ts, "ccii",    &refFlag, &fixBinsFlag, &len, &lenref);
  1001.     NX_ZONEMALLOC( [self zone], data, char, len );
  1002.     NX_ZONEMALLOC( [self zone], reffilename, char, lenref+1 );
  1003.     NXReadType(  ts, "*",       &reffilename);
  1004.     if ( NXTypedStreamClassVersion(ts, "Plot") >= INDEX_VERSION ) {
  1005.         NXReadType( ts, "i", &ntindex );
  1006.         hTuple = NXReadObject( ts );
  1007.     } else {
  1008.         ntindex = 0;
  1009.     hTuple = nil;
  1010.     }
  1011.     NXReadArray( ts, "c",       len, data );
  1012.     h_readMem( data, len,  &dlist, &ntlist );
  1013.     NX_FREE( data );
  1014.     disp = dlist[0];
  1015.     NXReadType(  ts, "c",      &cutHistFlag );
  1016.     if ( cutHistFlag ) {
  1017.         NXReadType( ts, "i",       &len );
  1018.     NX_ZONEMALLOC( [self zone], cutParms.cutFunc, char, len+1 );
  1019.     NXReadType( ts, "{*iffi}", &cutParms ); 
  1020.     NXReadType( ts, "i",       &cutNumber);
  1021.     }
  1022.     NXReadType(  ts, "i",       &count );
  1023.     if ( count ) {
  1024.         cutPlotStor = [[Storage allocFromZone:[self zone]] initCount:0
  1025.                              elementSize:sizeof(cutStorElem)
  1026.                          description:"@%*"];
  1027.     }
  1028.     for ( i = 0; i < count; i++ ) {
  1029.         cut.plot = NXReadObject( ts );
  1030.     if ( NXTypedStreamClassVersion(ts, "Plot") >= INDEX_VERSION ) {
  1031.         NXReadType( ts, "%", &cut.name );
  1032.     } else {
  1033.         cut.name = NXUniqueString("HippoPlot.NULL" );
  1034.     }
  1035.     if ( cut.plot ) {
  1036.         cut.name = [cut.plot name];
  1037.     }
  1038.     [cutPlotStor addElement:&cut.plot];
  1039.     }
  1040.     NXReadType( ts, "i", &count );
  1041.     if ( count ) {
  1042.         dependStor = [[Storage allocFromZone:[self zone]] initCount:0
  1043.                              elementSize:sizeof(dependStorElem)
  1044.                          description:"@%"];
  1045.     }
  1046.     for ( i = 0; i < count; i++ ) {
  1047.         new.plot = NXReadObject( ts );
  1048.     if ( NXTypedStreamClassVersion(ts, "Plot") >= INDEX_VERSION ) {
  1049.          NXReadType( ts, "%", &new.name );
  1050.     } else {
  1051.         new.name = NXUniqueString("HippoPlot.NULL" );
  1052.     }
  1053.     if ( new.plot ) {
  1054.         new.name = [new.plot name];
  1055.     }
  1056.         [dependStor addElement:&new];
  1057.     }
  1058.     return self;
  1059. }
  1060. - free
  1061. {
  1062.   /* disp should be attached, but it may not be */
  1063.     if ( disp != NULL ) h_freeDisp(disp);
  1064.     NX_FREE(reffilename);
  1065.     NX_FREE(cutParms.cutFunc);
  1066.     return [super free];
  1067. }
  1068. @end
  1069.